package com.stylefeng.guns.modular.prediction.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.stylefeng.guns.common.exception.BizExceptionEnum;
import com.stylefeng.guns.common.exception.BussinessException;
import com.stylefeng.guns.common.persistence.dao.RiskFactorMapper;
import com.stylefeng.guns.common.persistence.model.RiskFactor;
import com.stylefeng.guns.common.plugin.service.impl.BaseTreeableServiceImpl;
import com.stylefeng.guns.core.util.DoubleUtil;
import com.stylefeng.guns.modular.prediction.dao.RiskFactorDao;
import com.stylefeng.guns.modular.prediction.service.IRiskFactorService;
import com.stylefeng.guns.modular.prediction.transfer.FishBoneDto;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 事故致因 服务实现类
 * </p>
 *
 * @author xuziyang
 * @since 2018-04-11
 */
@Service
public class RiskFactorServiceImpl extends BaseTreeableServiceImpl<RiskFactorMapper, RiskFactor> implements IRiskFactorService {


    @Override
    public List<RiskFactor> findByPid(Integer pid) {
        EntityWrapper<RiskFactor> ew = new EntityWrapper<>();
        ew.eq("pid", pid);
        return selectList(ew);
    }

    @Override
    public List<RiskFactor> analyse(Integer rootId) {
        RiskFactor root = getRoot(rootId);
        List<RiskFactor> riskFactorList = this.findByPid(root.getId());

        for (RiskFactor riskFactor : riskFactorList) {
            recursionAnalyse(riskFactor);
        }
        return riskFactorList;
    }

    private void recursionAnalyse(RiskFactor parent) {

        List<RiskFactor> children = this.findByPid(parent.getId());

        if (CollectionUtils.isEmpty(children)) {
            return;
        }

        for (RiskFactor child : children) {
            recursionAnalyse(child);
        }

        Double median = 0d;
        Double upper = 0d;
        Double flo = 0d;

        for (int i = 0; i < children.size(); i++) {

            Double medianFac = 1d;
            Double upperFac = 1d;
            Double floFac = 1d;

            for (int j = 0; j < i; j++) {
                medianFac = DoubleUtil.mul(medianFac, DoubleUtil.sub(1, children.get(j).getMedian()));
                upperFac = DoubleUtil.mul(upperFac, DoubleUtil.sub(1, children.get(j).getUpper()));
                floFac = DoubleUtil.mul(floFac, DoubleUtil.sub(1, children.get(j).getFlo()));
            }
            if (children.get(i).getMedian() == null) {
                continue;
            }

            median = DoubleUtil.add(median, DoubleUtil.mul(DoubleUtil.mul(medianFac, children.get(i).getMedian())));
            upper = DoubleUtil.add(upper, DoubleUtil.mul(DoubleUtil.mul(upperFac, children.get(i).getUpper())));
            flo = DoubleUtil.add(flo, DoubleUtil.mul(DoubleUtil.mul(floFac, children.get(i).getFlo())));
        }

        if (parent.getMedian() != null) {
            parent.setMedian(DoubleUtil.mul(parent.getMedian(), median));
        } else {
            parent.setMedian(median);
        }

        if (parent.getUpper() != null) {
            parent.setUpper(DoubleUtil.mul(parent.getUpper(), upper));
        } else {
            parent.setUpper(upper);
        }

        if (parent.getFlo() != null) {
            parent.setFlo(DoubleUtil.mul(parent.getFlo(), flo));
        } else {
            parent.setFlo(flo);
        }
    }


    private RiskFactor getRoot(Integer rootId) {
        RiskFactor riskFactor = this.selectById(rootId);
        if (riskFactor != null) {
            return riskFactor;
        }

        EntityWrapper<RiskFactor> ew = new EntityWrapper<>();
        ew.where("pid = 0");
        List<RiskFactor> list = this.selectList(ew);

        if (list.size() == 0) {
            throw new BussinessException(BizExceptionEnum.DB_RESOURCE_NULL);
        }

        if (list.size() == 1) {
            return list.get(0);
        }


        Optional<RiskFactor> rootOp = list.stream().filter(rk -> rk.getStatus() == 1).findFirst();
        if (rootOp.isPresent()) {
            return rootOp.get();
        } else {
            return list.get(0);
        }
    }


    @Override
    @Transactional
    public void updateStatusDefault(Integer id) {
        RiskFactor riskFactor = this.selectById(id);
        if (riskFactor == null) {
            throw new BussinessException(BizExceptionEnum.REQUEST_NULL);
        }
        if (riskFactor.getPid() != 0) {
            throw new BussinessException(BizExceptionEnum.REQUEST_INVALIDATE);
        }
        EntityWrapper<RiskFactor> ew = new EntityWrapper<>();
        ew.where("status = 1");
        selectList(ew).stream().forEach(rk -> {
            rk.setStatus(0);
            updateById(rk);
        });

        riskFactor.setStatus(1);
        updateById(riskFactor);
    }


}
